home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 2108 / 2108.xpi / content / manage.js < prev    next >
Text File  |  2009-10-21  |  17KB  |  510 lines

  1. var stylishManage = {
  2.  
  3.     filterText: "",
  4.     strings: null,
  5.  
  6.     init: function() {
  7.         this.strings = document.getElementById("stylishStrings");
  8.         this.build(true);
  9.  
  10.         var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
  11.         observerService.addObserver(this.observer, "stylish-style-change", false);
  12.         observerService.addObserver(this.observer, "stylish-style-delete", false);
  13.         //observerService.addObserver(this.observer, "stylish-style-update-check-done", false);
  14.  
  15.         var prefService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).QueryInterface(Components.interfaces.nsIPrefBranch2);
  16.         prefService.addObserver("extensions.stylish.styleRegistrationEnabled", this.observer, false);
  17.         if (!prefService.getBoolPref("extensions.stylish.styleRegistrationEnabled")) {
  18.             this.addStylesOffNotification();
  19.         }
  20.     },
  21.  
  22.     destroy: function() {
  23.         var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
  24.         observerService.removeObserver(this.observer, "stylish-style-change");
  25.         observerService.removeObserver(this.observer, "stylish-style-delete");
  26.         //observerService.removeObserver(this.observer, "stylish-style-update-check-done");
  27.  
  28.         var prefService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).QueryInterface(Components.interfaces.nsIPrefBranch2);
  29.         prefService.removeObserver("extensions.stylish.styleRegistrationEnabled", this.observer);
  30.  
  31.         this.saveUIState();
  32.     },
  33.  
  34.     observer: {
  35.         observe: function(subject, topic, data) {
  36.             if (topic == "nsPref:changed") {
  37.                 if (subject.QueryInterface(Components.interfaces.nsIPrefBranch2).getBoolPref(data)) {
  38.                     document.getElementById("styles-container").removeAllNotifications(false);
  39.                 } else {
  40.                     stylishManage.addStylesOffNotification();
  41.                 }
  42.                 return;
  43.             }
  44.             /*if (topic == "stylish-style-update-check-done") {
  45.                 stylishManage.updateNext();
  46.                 return;
  47.             }*/
  48.             var container = document.getElementById("styles")
  49.             // if we're deleting the current selection, it's no longer the current selection
  50.             if (topic == "stylish-style-delete" && container.currentSelection && container.currentSelection.styleObject.id == subject.id) {
  51.                 container.currentSelection = null;
  52.             }
  53.             // don't rebuild on update because then we'd lose all the update UI
  54.             if (data != "update") {
  55.                 stylishManage.build();
  56.             }
  57.         }
  58.     },
  59.  
  60.     addStylesOffNotification: function() {
  61.         var container = document.getElementById("styles-container");
  62.         function callback(box, button) {
  63.             Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).QueryInterface(Components.interfaces.nsIPrefBranch2).setBoolPref("extensions.stylish.styleRegistrationEnabled", true);
  64.         }
  65.         container.appendNotification(stylishManage.strings.getString("styleRegistrationOff"), "stylesOff", null, container.PRIORITY_WARNING_LOW, [{label: stylishManage.strings.getString("styleRegistrationTurnOn"), accessKey: stylishManage.strings.getString("styleRegistrationTurnOn.ak"), callback: callback}]);
  66.     },
  67.  
  68.     build: function(skipSaveUIState) {
  69.  
  70.         if (skipSaveUIState !== true) {
  71.             this.saveUIState();
  72.         }
  73.  
  74.         // store the previously selected id and group, if any
  75.         var container = document.getElementById("styles");
  76.         var previousId, previousGroupId;
  77.         if (container.currentSelection && container.currentSelection.parentNode) {
  78.             previousId = container.currentSelection.styleObject.id;
  79.             if (container.currentSelection.parentNode.nodeName == "style-container") {
  80.                 previousGroupId = container.currentSelection.parentNode.id;
  81.             }
  82.         }
  83.  
  84.         var service = Components.classes["@userstyles.org/style;1"].getService(Components.interfaces.stylishStyle);
  85.         var styles = service.list(service.REGISTER_STYLE_ON_CHANGE, {});
  86.         var deck = document.getElementById("styles-deck");
  87.         if (styles.length == 0) {
  88.             deck.selectedIndex = 1;
  89.             return;
  90.         }
  91.         deck.selectedIndex = 0;
  92.         styles = styles.filter(this.filter);
  93.         var fragment = document.createDocumentFragment();
  94.         var groups = this.group(styles);
  95.         groups.forEach(function(g) {
  96.             // don't show empty groups
  97.             if (g.styles.length == 0)
  98.                 return;
  99.             // parent is what we'll dump the style items into
  100.             var parent;
  101.             // set up the group header, if available
  102.             if (g.id) {
  103.                 var heading = document.createElement("style-container");
  104.                 heading.setAttribute("id", g.id);
  105.                 heading.setAttribute("label", g.label || stylishManage.strings.getString(g.id));
  106.                 heading.setAttribute("group-type", g.type);
  107.                 heading.setAttribute("group-value", g.value);
  108.                 fragment.appendChild(heading);
  109.                 parent = heading;
  110.             } else {
  111.                 parent = fragment;
  112.             }
  113.             g.styles.sort(stylishManage.sortName).forEach(function(s) {
  114.                 var item = document.createElement("richlistitem");
  115.                 item.setAttribute("style-id", s.id);
  116.                 item.styleObject = s;
  117.                 parent.appendChild(item);
  118.             });
  119.         });
  120.  
  121.         // xbl destructors aren't called when removing, so we have to ensure things are torn down
  122.         function removeChildren(e) {
  123.             while (e.hasChildNodes()) {
  124.                 var child = e.firstChild;
  125.                 if (child.hasChildNodes()) {
  126.                     removeChildren(child);
  127.                 }
  128.                 if ("destroy" in child) {
  129.                     child.destroy();
  130.                 }
  131.                 e.removeChild(child);
  132.             }    
  133.         }
  134.         removeChildren(container);
  135.         
  136.         container.appendChild(fragment);
  137.  
  138.         this.loadUIState();
  139.  
  140.         // restore the previous selection
  141.         // restore in the correct group, if it's still there
  142.         if (previousGroupId) {
  143.             selectionBase = document.getElementById(previousGroupId);
  144.             if (selectionBase) {
  145.                 selectionBase.removeAttribute("closed");
  146.                 var possibleSelections = selectionBase.getElementsByAttribute("style-id", previousId);
  147.                 if (possibleSelections.length > 0) {
  148.                     possibleSelections[0].click();
  149.                     return;
  150.                 }
  151.             }
  152.         }
  153.         // restore any instance of the style
  154.         if (previousId) {
  155.             var newSelections = container.getElementsByAttribute("style-id", previousId);
  156.             if (newSelections.length > 0) {
  157.                 newSelections[0].click();
  158.             }
  159.         }
  160.     },
  161.  
  162.     group: function(styles) {
  163.         var groups = [];
  164.         var groupType = document.getElementById("styles-sort").value;
  165.         // name is not grouped
  166.         if (groupType == "name") {
  167.             groups.push({styles: styles});
  168.         // enabled goes into enabled/disabled
  169.         } else if (groupType == "enabled") {
  170.             var enabled = [];
  171.             var disabled = [];
  172.             styles.forEach(function(s) {
  173.                 if (s.enabled)
  174.                     enabled.push(s);
  175.                 else
  176.                     disabled.push(s);
  177.             });
  178.             groups.push({id:"groupEnabledTrue", styles: enabled, type: "enabled", value: "true"});
  179.             groups.push({id:"groupEnabledFalse", styles: disabled, type: "enabled", value: "false"});
  180.         // by type. styles have 0 to many types
  181.         } else if (groupType == "type") {
  182.             var app = [];
  183.             var site = [];
  184.             var global = [];
  185.             var none = [];
  186.             styles.forEach(function(s) {
  187.                 var types = s.getMeta("type", {});
  188.                 if (types.length == 0) {
  189.                     none.push(s);
  190.                     return;
  191.                 }
  192.                 if (types.indexOf("app") > -1)
  193.                     app.push(s);
  194.                 if (types.indexOf("global") > -1)
  195.                     global.push(s);
  196.                 if (types.indexOf("site") > -1)
  197.                     site.push(s);
  198.             });
  199.             groups.push({id:"groupTypeApp", styles: app, type: "type", value: "app"});
  200.             groups.push({id:"groupTypeGlobal", styles: global, type: "type", value: "global"});
  201.             groups.push({id:"groupTypeSite", styles: site, type: "type", value: "site"});
  202.             groups.push({id:"groupTypeNone", styles: none, type: "type", value: ""});
  203.         // by tag. styles have 0 to many tags
  204.         } else if (groupType == "tag") {
  205.             var tagGroups = {};
  206.             var none = [];
  207.             styles.forEach(function(s) {
  208.                 var types = s.getMeta("tag", {});
  209.                 // filter out whitespace ones. they shouldn't exist, but we need to make sure because they can hork us up
  210.                 types.filter(function(tag) {
  211.                     return !/^\s*$/.test(tag);
  212.                 }).forEach(function(tag) {
  213.                     if (tag in tagGroups)
  214.                         tagGroups[tag].push(s);
  215.                     else
  216.                         tagGroups[tag] = [s];
  217.                 });
  218.                 if (types.length == 0) {
  219.                     none.push(s);
  220.                     return;
  221.                 }
  222.             });
  223.             for (i in tagGroups) {
  224.                 groups.push({id:"groupTag" + i, label: i, styles: tagGroups[i], type: "tag", value: i});
  225.             }
  226.             groups.sort(function(a, b) {
  227.                 return stylishManage.sortAlpha(a.label, b.label);
  228.             });
  229.             if (none.length > 0) {
  230.                 groups.push({id:"groupTagNone", styles: none, type: "tag", value: ""});
  231.             }
  232.         }
  233.         return groups;
  234.     },
  235.  
  236.     sortName: function(a, b) {
  237.         return stylishManage.sortAlpha(a.name, b.name);
  238.     },
  239.  
  240.     sortAlpha: function(a, b) {
  241.         a = a.toLowerCase();
  242.         b = b.toLowerCase();
  243.         if (a > b)
  244.             return 1;
  245.         if (b > a)
  246.             return -1;
  247.         return 0;
  248.     },
  249.  
  250.     newStyle: function() {
  251.         var style = Components.classes["@userstyles.org/style;1"].createInstance(Components.interfaces.stylishStyle);
  252.         style.mode = style.CALCULATE_META | style.REGISTER_STYLE_ON_CHANGE;
  253.         style.init(null, null, null, null, "", false, null);
  254.         stylishCommon.openEdit(stylishCommon.getWindowName("stylishEdit"), {style: style});
  255.     },
  256.  
  257.     filter: function(style) {
  258.         if (stylishManage.filterText.length == 0)
  259.             return true;
  260.         var filterWords = stylishManage.filterText.split(/\s+/);
  261.         var styleWords = style.name.toLowerCase();
  262.         var styleTypes = style.getMeta("type", {});
  263.         var styleTags = style.getMeta("tag", {});
  264.         return filterWords.every(function(word) {
  265.             //straight up word match
  266.             if (styleWords.indexOf(word) > -1)
  267.                 return true;
  268.             //types
  269.             if (styleTypes.indexOf(word) > -1)
  270.                 return true;
  271.             //tags
  272.             if (styleTags.some(function(tag) {
  273.                 return tag.indexOf(word) > -1;
  274.             }))
  275.                 return true;
  276.             //urls
  277.             return style.appliesToUrl(stylishManage.convertToUrl(word));
  278.         });
  279.     },
  280.  
  281.     updateFilter: function(text) {
  282.         this.filterText = text.toLowerCase();
  283.         this.build();
  284.     },
  285.  
  286.     convertToUrl: function(text) {
  287.         //if it has a colon, it may already be an url
  288.         if (/:/.test(text))
  289.             return text;
  290.         //if not, assume http
  291.         return "http://" + text;
  292.     },
  293.  
  294.     updateAll: function() {
  295.         var service = Components.classes["@userstyles.org/style;1"].getService(Components.interfaces.stylishStyle);
  296.         service.list(service.REGISTER_STYLE_ON_CHANGE, {}).forEach(function(style) {
  297.             style.checkForUpdates()
  298.         });
  299.     },
  300.  
  301.     /*
  302.     currentUpdateStyles: [],
  303.     currentUpdateIndex: null,
  304.     updateAll: function() {
  305.         //doing them all at once overwhelms the site
  306.         var service = Components.classes["@userstyles.org/style;1"].getService(Components.interfaces.stylishStyle);
  307.         stylishManage.currentUpdateStyles = service.list(service.REGISTER_STYLE_ON_CHANGE, {});
  308.         stylishManage.currentUpdateIndex = 0;
  309.         stylishManage.updateNext();
  310.     },
  311.  
  312.     updateNext: function() {
  313.         var i = stylishManage.currentUpdateIndex;
  314.         stylishManage.currentUpdateIndex++;
  315.         if (i >= stylishManage.currentUpdateStyles.length) {
  316.             //we're done
  317.             return;
  318.         }
  319.         stylishManage.currentUpdateStyles[i].checkForUpdates();
  320.     },*/
  321.  
  322.     copyInfo: function() {
  323.         Components.classes["@userstyles.org/style;1"].getService(Components.interfaces.stylishStyle).copyListToClipboard();
  324.     },
  325.  
  326.     handleKeyPress: function(event) {
  327.         if (event.keyCode != 38 && event.keyCode != 40)
  328.             return;
  329.         var styles = document.getElementById("styles")
  330.         var currentSelection = styles.currentSelection;
  331.         var nextSelection = null;
  332.         if (!currentSelection) {
  333.             // no previous selection, select the first one
  334.             nextSelection = styles.firstChild;
  335.         } else {
  336.             var items = styles.getElementsByTagName("richlistitem")
  337.             var index;
  338.             for (index = 0; index < items.length; index++) {
  339.                 if (items[index] == currentSelection) {
  340.                     break;
  341.                 }
  342.             }
  343.             function move() {
  344.                 if (event.keyCode == 38) {
  345.                     if (index == 0) {
  346.                         return false;
  347.                     }
  348.                     index--;
  349.                 } else {
  350.                     if (index == items.length - 1) {
  351.                         return false;
  352.                     }
  353.                     index++;
  354.                 }
  355.                 return true;
  356.             }
  357.             while(move()) {
  358.                 var item = items[index];
  359.                 // skip over items in collapsed containers
  360.                 if (item.parentNode.nodeName != "style-container" || item.parentNode.getAttribute("closed") != "true") {
  361.                     nextSelection = item;
  362.                     break;
  363.                 }
  364.             }
  365.         }
  366.         if (nextSelection) {
  367.             nextSelection.click();
  368.             styles.ensureElementIsVisible(nextSelection);
  369.         }
  370.     },
  371.  
  372.     // workaround for bug 115296
  373.     loadUIState: function() {
  374.         var prefService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).QueryInterface(Components.interfaces.nsIPrefBranch2);
  375.         prefService.getCharPref("extensions.stylish.closedContainers").split(" ").forEach(function(id) {
  376.             if (id) {
  377.                 var element = document.getElementById(id);
  378.                 if (element) {
  379.                     element.setAttribute("closed", "true");
  380.                 };
  381.             }
  382.         });
  383.     },
  384.  
  385.     saveUIState: function() {
  386.         var prefService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).QueryInterface(Components.interfaces.nsIPrefBranch2);
  387.         // We can't just create a new list of ids of things that are closed because the user may have switched 
  388.         // grouping and we wouldn't want to lose all their settings from the other grouping.
  389.         var ids = [];
  390.         // Check things that were closed last time, and remove them if they're open.
  391.         prefService.getCharPref("extensions.stylish.closedContainers").split(" ").forEach(function(id) {
  392.             if (id) {
  393.                 var element = document.getElementById(id);
  394.                 if (!element || element.getAttribute("closed") == "true") {
  395.                     ids.push(id);
  396.                 }
  397.             }
  398.         });
  399.         // Now, get the ids of things that are closed that aren't in the list already.
  400.         ids = ids.concat(Array.filter(document.getElementsByTagName("style-container"), function(element) {
  401.             return element.getAttribute("closed") == "true";
  402.         }).map(function(element) {
  403.             return element.id;
  404.         }).filter(function(id) {
  405.             return ids.indexOf(id) == -1;
  406.         }));
  407.         // And save them
  408.         prefService.setCharPref("extensions.stylish.closedContainers", ids.join(" "));
  409.     },
  410.  
  411.     dragService: Components.classes["@mozilla.org/widget/dragservice;1"].getService().QueryInterface(Components.interfaces.nsIDragService),
  412.     dragObserver: {
  413.         onDragStart: function (event, transferData, action) {
  414.             var style = event.target.styleObject;
  415.             //var selection = document.getElementById("styles").currentSelection;
  416.             var selection = event.target;
  417.             var data = selection.styleObject.id + " " + selection.parentNode.getAttribute("group-value");
  418.  
  419.             transferData.data = new TransferData();
  420.             transferData.data.addDataForFlavour("text/stylish-move", data);
  421.         },
  422.         getSupportedFlavours: function () {
  423.             var flavours = new FlavourSet();
  424.             flavours.appendFlavour("text/stylish-move");
  425.             return flavours;
  426.         },
  427.         onDrop: function(event, transferData, session) {
  428.             var data = transferData.data.split(" ");
  429.             var styleId = data[0];
  430.             var originalGroupValue = data[1];
  431.  
  432.             var service = Components.classes["@userstyles.org/style;1"].getService(Components.interfaces.stylishStyle);
  433.             style = service.find(styleId, service.REGISTER_STYLE_ON_CHANGE | service.CALCULATE_META);
  434.  
  435.             var group = stylishManage.dragObserver.getGroup(event);
  436.             if (!group) {
  437.                 Component.utils.reportError("Could not determine destination group.");
  438.             }
  439.  
  440.             switch (group.getAttribute("group-type")) {
  441.                 case "enabled":
  442.                     style.enabled = group.getAttribute("group-value");
  443.                     style.save();
  444.                     break;
  445.                 case "tag":
  446.                     if (originalGroupValue != "") {
  447.                         style.removeMeta("tag", originalGroupValue);
  448.                     }
  449.                     if (group.getAttribute("group-value") != "" && style.getMeta("tag", {}).indexOf(group.getAttribute("group-value")) == -1) {
  450.                         style.addMeta("tag", group.getAttribute("group-value"));
  451.                     }
  452.                     style.save();
  453.                     break;
  454.                 default:
  455.                     Components.utils.reportError("Unknown group type - '" + group.getAttribute("group-type") + "'.");
  456.             }
  457.         },
  458.         onDragOver: function (event, flavour, session) {
  459.             var dragSession = stylishManage.dragService.getCurrentSession();
  460.             session.canDrop = this.canDrop(event, dragSession);
  461.         },
  462.         canDrop: function(event, dragSession) {
  463.             var group = stylishManage.dragObserver.getGroup(event);
  464.             if (!group)
  465.                 return false;
  466.             var groupValue = group.getAttribute("group-value");
  467.  
  468.             var td = nsTransferable.createTransferable();
  469.             td.addDataFlavor("text/stylish-move");
  470.             dragSession.getData(td, 0);
  471.             var data = {};
  472.             td.getTransferData("text/stylish-move", data, {});
  473.             data = data.value.QueryInterface(Components.interfaces.nsISupportsString).data.split(" ");
  474.             var styleId = data[0];
  475.             var originalGroupValue = data[1];
  476.  
  477.             var service = Components.classes["@userstyles.org/style;1"].getService(Components.interfaces.stylishStyle);
  478.             var style = service.find(styleId, 0);
  479.  
  480.             switch (group.getAttribute("group-type")) {
  481.                 case "enabled":
  482.                     if (style.enabled == new Boolean(groupValue)) {
  483.                         return false;
  484.                     }
  485.                     break;
  486.                 case "tag":
  487.                     if (style.getMeta("tag", {}).indexOf(groupValue) > -1) {
  488.                         return false;
  489.                     }
  490.                     break;
  491.                 default:
  492.                     return false;
  493.             }
  494.             return true;
  495.         },
  496.         getGroup: function(event) {
  497.             var group = event.target;
  498.             while (group && group.nodeName != "style-container") {
  499.                 group = group.parentNode;
  500.             }
  501.             return group;
  502.         }
  503.  
  504.     }
  505. }
  506.  
  507. window.addEventListener("load", function(){stylishManage.init()}, false);
  508. window.addEventListener("unload", function(){stylishManage.destroy()}, false);
  509.  
  510.